<template>
  <div class="model-manage">
    <a-alert
      message="自定义算法管理"
      description="本页面用于管理YOLO自定义检测算法的类别标签和模型文件。标签配置全局生效,模型文件可在算法配置页面中选择使用。"
      type="info"
      show-icon
      closable
      style="margin-bottom: 16px"
    />

    <!-- 标签管理区域 -->
    <a-card title="YOLO类别标签管理" style="margin-bottom: 24px" :bordered="false">
      <template #extra>
        <a-space>
          <a-button type="primary" @click="handleEditLabels" :loading="labelsLoading">
            <template #icon><tags-outlined /></template>
            编辑标签
          </a-button>
          <a-tag color="blue">当前标签数: {{ labelCount }}</a-tag>
        </a-space>
      </template>

      <div class="labels-preview">
        <a-empty v-if="labelCount === 0" description="暂无标签配置,点击上方按钮开始配置" />
        <div v-else class="labels-list">
          <a-tag v-for="(name, id) in labelPreview" :key="id" color="processing" style="margin: 4px">
            {{ id }}: {{ name }}
          </a-tag>
          <a-tag v-if="labelCount > 20" color="default" style="margin: 4px">
            ... 还有 {{ labelCount - 20 }} 个标签
          </a-tag>
        </div>
      </div>
    </a-card>

    <!-- 模型文件管理区域 -->
    <a-card title="YOLO模型文件管理" :bordered="false">
      <template #extra>
        <a-space>
          <a-button type="primary" @click="handleAdd">
            <template #icon><plus-outlined /></template>
            上传模型
          </a-button>
          <a-button @click="fetchModelList" :loading="tableLoading">
            <template #icon><reload-outlined /></template>
            刷新列表
          </a-button>
          <a-tag color="green">模型总数: {{ pagination.total }}</a-tag>
        </a-space>
      </template>

      <a-table
        :dataSource="modelList"
        :columns="columns"
        :loading="tableLoading"
        :pagination="pagination"
        @change="handleTableChange"
        rowKey="filename"
      >
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'filename'">
          <div class="file-cell">
            <file-outlined style="margin-right: 8px; color: #1890ff" />
            <span class="filename-text">{{ record.filename }}</span>
          </div>
        </template>
        <template v-else-if="column.key === 'size'">
          {{ formatFileSize(record.size) }}
        </template>
        <template v-else-if="column.key === 'upload_time'">
          {{ formatDateTime(record.upload_time) }}
        </template>
        <template v-else-if="column.key === 'description'">
          <a-tooltip :title="record.description || '无描述'">
            <span class="description-text">{{ record.description || '-' }}</span>
          </a-tooltip>
        </template>
        <template v-else-if="column.key === 'num_classes'">
          <a-tag :color="record.num_classes > 0 ? 'green' : 'default'">
            {{ record.num_classes || 0 }} 类
          </a-tag>
        </template>
        <template v-else-if="column.key === 'actions'">
          <a-space>
            <a-tooltip title="下载模型">
              <a-button type="link" size="small" @click="downloadModelFile(record)">
                <template #icon><download-outlined /></template>
              </a-button>
            </a-tooltip>
            <a-tooltip title="编辑描述">
              <a-button type="link" size="small" @click="handleEditDescription(record)">
                <template #icon><edit-outlined /></template>
              </a-button>
            </a-tooltip>
            <a-tooltip title="删除模型">
              <a-button type="link" danger size="small" @click="deleteModelById(record.filename)">
                <template #icon><delete-outlined /></template>
              </a-button>
            </a-tooltip>
          </a-space>
        </template>
      </template>
      </a-table>
    </a-card>

    <!-- 上传模型对话框 -->
    <a-modal
      v-model:visible="modalVisible"
      title="上传YOLO模型"
      :confirm-loading="uploadLoading"
      @ok="handleModalOk"
      @cancel="handleModalCancel"
      width="600px"
    >
      <a-alert
        message="模型文件要求"
        type="warning"
        show-icon
        style="margin-bottom: 16px"
      >
        <template #description>
          <ul style="margin: 8px 0; padding-left: 20px;">
            <li>支持格式: .bin(海思)、.onnx、.pt(PyTorch)、.om(昇腾)</li>
            <li>文件大小: 最大100MB</li>
            <li>模型输入: 建议1024x576或640x640</li>
          </ul>
        </template>
      </a-alert>

      <a-upload
        v-model:file-list="uploadFileList"
        :before-upload="beforeUpload"
        :multiple="false"
        :disabled="uploadLoading"
        :max-count="1"
      >
        <a-button :disabled="uploadLoading">
          <upload-outlined />
          选择模型文件
        </a-button>
      </a-upload>

      <a-form layout="vertical" style="margin-top: 16px">
        <a-form-item label="模型描述" required>
          <a-textarea
            v-model:value="modelDescription"
            placeholder="请输入模型描述,例如:YOLOv8n 80类COCO模型、YOLOv5自定义3类安全帽检测模型等"
            :rows="4"
            :disabled="uploadLoading"
            :maxlength="200"
            show-count
          />
        </a-form-item>
      </a-form>

      <div v-if="uploadLoading" class="upload-progress">
        <a-progress :percent="uploadProgress" :status="uploadProgressStatus" />
        <div class="upload-progress-text">{{ uploadStatusText }}</div>
      </div>
    </a-modal>

    <!-- 编辑描述对话框 -->
    <a-modal
      v-model:visible="editDescModalVisible"
      title="编辑模型描述"
      @ok="handleSaveDescription"
      @cancel="editDescModalVisible = false"
    >
      <a-form layout="vertical">
        <a-form-item label="模型文件名">
          <a-input :value="editingModel?.filename" disabled />
        </a-form-item>
        <a-form-item label="模型描述" required>
          <a-textarea
            v-model:value="editingDescription"
            placeholder="请输入模型描述"
            :rows="4"
            :maxlength="200"
            show-count
          />
        </a-form-item>
      </a-form>
    </a-modal>

    <!-- 下载进度对话框 -->
    <a-modal
      v-model:visible="downloadModalVisible"
      title="下载模型"
      :footer="null"
      :closable="!downloadingModel"
      :maskClosable="false"
    >
      <div v-if="downloadingModel" class="download-progress">
        <a-alert
          :message="`正在下载: ${downloadingModel.filename}`"
          type="info"
          show-icon
        />
        <a-progress :percent="downloadProgress" style="margin-top: 16px" />
        <div style="margin-top: 8px; text-align: center; color: rgba(0,0,0,0.45)">
          {{ formatFileSize(downloadingModel.size) }}
        </div>
      </div>
    </a-modal>

    <!-- YOLO标签配置对话框 -->
    <a-modal
      v-model:visible="labelsModalVisible"
      title="YOLO全局类别标签配置"
      :confirm-loading="labelsLoading"
      @ok="handleSaveLabels"
      @cancel="labelsModalVisible = false"
      width="900px"
      :bodyStyle="{ maxHeight: '600px', overflowY: 'auto' }"
    >
      <a-alert
        message="全局配置说明"
        type="warning"
        show-icon
        style="margin-bottom: 16px"
      >
        <template #description>
          <div>这是所有YOLO算法共享的全局类别标签配置。</div>
          <div>修改后将影响所有使用YOLOv8检测的算法实例,配置会立即生效。</div>
        </template>
      </a-alert>
      <ClassLabelEditor v-model="currentLabels" />
    </a-modal>
  </div>
</template>

<script>
import { defineComponent, ref, onMounted, computed } from 'vue';
import { message, Modal } from 'ant-design-vue';
import {
  UploadOutlined,
  DownloadOutlined,
  DeleteOutlined,
  EditOutlined,
  FileOutlined,
  PlusOutlined,
  ReloadOutlined,
  TagsOutlined
} from '@ant-design/icons-vue';
import { uploadModelFile, getModelList, downloadModel, deleteModel } from '../../api/model';
import { getModelLabels, updateModelLabels } from '../../api/config';
import ClassLabelEditor from './ClassLabelEditor.vue';

export default defineComponent({
  name: 'ModelManage',
  components: {
    UploadOutlined,
    DownloadOutlined,
    DeleteOutlined,
    EditOutlined,
    FileOutlined,
    PlusOutlined,
    ReloadOutlined,
    TagsOutlined,
    ClassLabelEditor
  },
  setup() {
    // 状态管理
    const modalVisible = ref(false);
    const uploadFileList = ref([]);
    const modelDescription = ref('');
    const uploadLoading = ref(false);
    const uploadProgress = ref(0);
    const uploadStatusText = ref('');
    const tableLoading = ref(false);
    const modelList = ref([]);
    const downloadModalVisible = ref(false);
    const downloadingModel = ref(null);
    const downloadProgress = ref(0);
    const editDescModalVisible = ref(false);
    const editingModel = ref(null);
    const editingDescription = ref('');
    const labelsModalVisible = ref(false);
    const labelsLoading = ref(false);
    const currentLabels = ref([]);

    const pagination = ref({
      current: 1,
      pageSize: 10,
      total: 0,
      showSizeChanger: true,
      pageSizeOptions: ['10', '20', '50'],
      showTotal: (total) => `总共 ${total} 项`
    });

    // 表格列定义
    const columns = [
      {
        title: '模型文件',
        key: 'filename',
        width: 180,
        ellipsis: true
      },
      {
        title: '文件大小',
        key: 'size',
        width: 100
      },
      {
        title: '类别数',
        key: 'num_classes',
        width: 90
      },
      {
        title: '模型描述',
        key: 'description',
        ellipsis: true
      },
      {
        title: '上传时间',
        key: 'upload_time',
        width: 170
      },
      {
        title: '操作',
        key: 'actions',
        width: 150,
        fixed: 'right'
      }
    ];

    // 上传进度状态
    const uploadProgressStatus = computed(() => {
      if (uploadProgress.value === 100) return 'success';
      return 'active';
    });

    // 标签数量
    const labelCount = computed(() => {
      if (!currentLabels.value || typeof currentLabels.value !== 'object') {
        return 0;
      }
      return Object.keys(currentLabels.value).length;
    });

    // 标签预览 (只显示前20个)
    const labelPreview = computed(() => {
      if (!currentLabels.value || typeof currentLabels.value !== 'object') {
        return {};
      }
      const entries = Object.entries(currentLabels.value).slice(0, 20);
      return Object.fromEntries(entries);
    });

    // 格式化文件大小
    const formatFileSize = (bytes) => {
      if (bytes === 0) return '0 Bytes';
      const k = 1024;
      const sizes = ['Bytes', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    };

    // 格式化时间
    const formatDateTime = (timestamp) => {
      if (!timestamp) return '-';

      try {
        // 后端使用的是 std::filesystem::last_write_time().time_since_epoch().count()
        // 这返回的是纳秒级的tick计数,需要转换为毫秒
        const milliseconds = Math.floor(timestamp / 1000000); // 纳秒转毫秒

        const date = new Date(milliseconds);

        // 检查日期是否有效
        if (isNaN(date.getTime())) {
          console.warn('无效的时间戳:', timestamp);
          return '-';
        }

        // 格式化为本地时间
        return date.toLocaleString('zh-CN', {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
          hour: '2-digit',
          minute: '2-digit',
          second: '2-digit'
        });
      } catch (error) {
        console.error('时间格式化失败:', timestamp, error);
        return '-';
      }
    };

    // 文件上传前的验证
    const beforeUpload = (file) => {
      const isValidType = /\.(bin|onnx|pt|om)$/i.test(file.name);
      if (!isValidType) {
        message.error('请上传YOLO模型文件(.bin、.onnx、.pt、.om)');
        return false;
      }

      const isLt100M = file.size / 1024 / 1024 < 100;
      if (!isLt100M) {
        message.error('模型文件大小不能超过100MB');
        return false;
      }

      return false; // 返回false阻止默认上传行为
    };

    // 处理添加模型
    const handleAdd = () => {
      modalVisible.value = true;
      uploadFileList.value = [];
      modelDescription.value = '';
      uploadProgress.value = 0;
      uploadStatusText.value = '';
    };

    // 处理模态框确认
    const handleModalOk = async () => {
      if (uploadFileList.value.length === 0) {
        message.warning('请先选择模型文件');
        return;
      }

      if (!modelDescription.value.trim()) {
        message.warning('请输入模型描述');
        return;
      }

      try {
        const file = uploadFileList.value[0].originFileObj;
        uploadLoading.value = true;
        uploadProgress.value = 0;

        const success = await uploadModelFile(
          file,
          (progress, current, total) => {
            uploadProgress.value = progress;
            uploadStatusText.value = `正在上传第 ${current}/${total} 块 (${progress}%)`;
          },
          modelDescription.value.trim()
        );

        if (success) {
          modalVisible.value = false;
          uploadFileList.value = [];
          modelDescription.value = '';
          fetchModelList(); // 刷新列表
          message.success('模型文件上传成功');
        }
      } catch (error) {
        console.error('上传处理失败:', error);
        message.error(`上传失败: ${error.message || '未知错误'}`);
      } finally {
        uploadLoading.value = false;
        uploadProgress.value = 0;
        uploadStatusText.value = '';
      }
    };

    // 处理模态框取消
    const handleModalCancel = () => {
      if (uploadLoading.value) {
        Modal.confirm({
          title: '确认取消',
          content: '文件正在上传中,确定要取消上传吗?',
          okText: '确认',
          cancelText: '继续上传',
          onOk: () => {
            uploadLoading.value = false;
            modalVisible.value = false;
            uploadFileList.value = [];
            modelDescription.value = '';
          }
        });
      } else {
        modalVisible.value = false;
        uploadFileList.value = [];
        modelDescription.value = '';
      }
    };

    // 获取模型列表
    const fetchModelList = async () => {
      try {
        tableLoading.value = true;
        const response = await getModelList();
        modelList.value = response.models || [];
        pagination.value.total = modelList.value.length;
      } catch (error) {
        console.error('获取模型列表失败:', error);
        message.error('获取模型列表失败: ' + (error.message || '未知错误'));
        modelList.value = [];
      } finally {
        tableLoading.value = false;
      }
    };

    // 表格分页变化时触发
    const handleTableChange = (pag) => {
      pagination.value.current = pag.current;
      pagination.value.pageSize = pag.pageSize;
    };

    // 编辑模型描述
    const handleEditDescription = (model) => {
      editingModel.value = model;
      editingDescription.value = model.description || '';
      editDescModalVisible.value = true;
    };

    // 保存模型描述
    const handleSaveDescription = async () => {
      // 注意: 当前后端API可能不支持单独更新描述
      // 这里需要根据实际后端API调整
      message.info('描述编辑功能待后端API支持');
      editDescModalVisible.value = false;

      // TODO: 调用后端API更新描述
      // await updateModelDescription(editingModel.value.filename, editingDescription.value);
      // fetchModelList();
    };

    // 下载模型
    const downloadModelFile = async (model) => {
      try {
        downloadModalVisible.value = true;
        downloadingModel.value = model;
        downloadProgress.value = 0;

        // 使用分块下载API
        const blob = await downloadModel(model.filename);

        // 创建下载链接
        const url = window.URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = model.filename;
        link.style.display = 'none';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        window.URL.revokeObjectURL(url);

        downloadProgress.value = 100;
        message.success('模型文件下载成功');

        // 延迟关闭对话框
        setTimeout(() => {
          downloadModalVisible.value = false;
          downloadingModel.value = null;
          downloadProgress.value = 0;
        }, 1000);
      } catch (error) {
        console.error('下载模型失败:', error);
        message.error('下载失败: ' + (error.message || '未知错误'));
        downloadModalVisible.value = false;
        downloadingModel.value = null;
        downloadProgress.value = 0;
      }
    };

    // 删除模型
    const deleteModelById = async (filename) => {
      Modal.confirm({
        title: '确认删除',
        content: `确定要删除模型"${filename}"吗? 此操作不可恢复!`,
        okText: '确认删除',
        okType: 'danger',
        cancelText: '取消',
        onOk: async () => {
          try {
            await deleteModel(filename);
            message.success('模型删除成功');
            fetchModelList(); // 刷新模型列表
          } catch (error) {
            console.error('删除模型失败:', error);
            message.error('删除失败: ' + (error.message || '未知错误'));
          }
        }
      });
    };

    // 编辑YOLO标签
    const handleEditLabels = async () => {
      try {
        labelsLoading.value = true;
        labelsModalVisible.value = true;

        // 加载现有标签(全局YOLOv8配置)
        const labels = await getModelLabels();
        currentLabels.value = labels;
      } catch (error) {
        console.error('加载类别标签失败:', error);
        message.error('加载类别标签失败: ' + (error.message || '未知错误'));
        labelsModalVisible.value = false;
      } finally {
        labelsLoading.value = false;
      }
    };

    // 配置类别标签 (已废弃,改用handleEditLabels)
    const handleConfigLabels = async (model) => {
      try {
        editingModel.value = model;
        labelsLoading.value = true;
        labelsModalVisible.value = true;

        // 加载现有标签(全局YOLOv8配置,不再需要filename)
        const labels = await getModelLabels();
        currentLabels.value = labels;
      } catch (error) {
        console.error('加载类别标签失败:', error);
        message.error('加载类别标签失败: ' + (error.message || '未知错误'));
        labelsModalVisible.value = false;
      } finally {
        labelsLoading.value = false;
      }
    };

    // 保存类别标签
    const handleSaveLabels = async () => {
      try {
        labelsLoading.value = true;

        // 保存标签(全局YOLOv8配置)
        await updateModelLabels(currentLabels.value);

        message.success('YOLO类别标签保存成功,配置已生效');
        labelsModalVisible.value = false;
      } catch (error) {
        console.error('保存类别标签失败:', error);
        message.error('保存类别标签失败: ' + (error.message || '未知错误'));
      } finally {
        labelsLoading.value = false;
      }
    };

    // 组件挂载时获取模型列表和标签
    onMounted(async () => {
      fetchModelList();

      // 加载标签配置
      try {
        const labels = await getModelLabels();
        currentLabels.value = labels;
      } catch (error) {
        console.error('初始加载标签失败:', error);
        currentLabels.value = {};
      }
    });

    return {
      modalVisible,
      uploadFileList,
      modelDescription,
      uploadLoading,
      uploadProgress,
      uploadStatusText,
      uploadProgressStatus,
      tableLoading,
      modelList,
      downloadModalVisible,
      downloadingModel,
      downloadProgress,
      editDescModalVisible,
      editingModel,
      editingDescription,
      labelsModalVisible,
      labelsLoading,
      currentLabels,
      labelCount,
      labelPreview,
      pagination,
      columns,
      formatFileSize,
      formatDateTime,
      beforeUpload,
      handleAdd,
      handleModalOk,
      handleModalCancel,
      handleTableChange,
      handleEditDescription,
      handleSaveDescription,
      downloadModelFile,
      deleteModelById,
      fetchModelList,
      handleEditLabels,
      handleConfigLabels,
      handleSaveLabels
    };
  }
});
</script>

<style scoped>
.model-manage {
  padding: 24px;
}

.labels-preview {
  min-height: 80px;
  padding: 16px 0;
}

.labels-list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.file-cell {
  display: flex;
  align-items: center;
}

.filename-text {
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 13px;
}

.description-text {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

:deep(.ant-upload-list) {
  margin-top: 16px;
}

.upload-progress {
  margin-top: 16px;
  padding: 16px;
  background: #f5f5f5;
  border-radius: 4px;
}

.upload-progress-text {
  margin-top: 8px;
  text-align: center;
  color: rgba(0, 0, 0, 0.65);
  font-size: 13px;
}

.download-progress {
  text-align: center;
  padding: 24px;
}

:deep(.ant-table) {
  font-size: 14px;
}

:deep(.ant-btn-link) {
  padding: 4px 8px;
}
</style>
